package com.woniu.adapter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.woniu.outlet.elasticSearch.FundESDao;
import com.woniu.outlet.elasticSearch.po.Fund;
import com.woniu.outlet.mysql.FundRelaMapper;
import com.woniu.outlet.mysql.po.FundRela;
import com.woniu.outlet.mysql.po.FundRelaExample;
import com.woniu.outlet.redis.FundRedisDao;
import com.woniu.outlet.redis.po.FundRedis;
import com.woniu.util.FundUtils;
import com.woniu.util.po.NetWorth;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

/**
 * @description:
 * @author: my
 * @time: 2021/4/20 10:17
 */
@Slf4j
@Component
public class FundAdapter {
    private FundRedisDao fundRedisDao;

    private FundRelaMapper fundRelaMapper;

    private FundESDao fundESDao;

    private FundUtils fundUtils;

    private StringRedisTemplate redisTemplate;

    public FundAdapter(FundRedisDao fundRedisDao, FundRelaMapper fundRelaMapper,
                       FundESDao fundESDao, FundUtils fundUtils,StringRedisTemplate redisTemplate) {
        this.fundRedisDao = fundRedisDao;
        this.fundRelaMapper = fundRelaMapper;
        this.fundESDao = fundESDao;
        this.fundUtils = fundUtils;
        this.redisTemplate = redisTemplate;
    }

    /**
     * 模糊查询
     * @param name
     * @return
     */
    @Transactional
    public List<Fund> fundSearch(String name){
        List<Fund> funds = fundESDao.searchByName(name);
        log.debug("从elasticsearch模糊查询");
        return funds;
    }
    /**
     * 获取基金折线图数据
     * @param code
     * @param month
     * @return
     * @throws URISyntaxException
     */
    @Transactional
    public List<NetWorth> FundGraph(String code, int month) throws URISyntaxException {
        List<NetWorth> netWorths = new ArrayList<>();
        log.debug("graph月份："+month);
        String s = redisTemplate.opsForValue().get("graph:" + code+month);
        if (s != null && !"".equals(s)) {
            List list = JSON.parseObject(s, List.class);
            for (Object o : list) {
                NetWorth netWorth = JSON.parseObject(o.toString(), NetWorth.class);
                netWorths.add(netWorth);
            }
            log.debug("从redis获取netWorth数据");
            return netWorths;
        }
        FundRedis fundRedis = fundUtils.getFundGraph(code, month);
        String data = fundRedis.getData();
        String netWorthData = JSON.parseObject(data).getString("netWorthData");
        List list = JSON.parseObject(netWorthData, List.class);
        int index = 1;
        int step = list.size() / 60;
        for (Object o : list) {
            if (step != 0 && index%step != 0){
                index++;
                continue;
            }
            index++;
            String[] strs = o.toString().replace("[", "").replace("\"", "").split(",");
            NetWorth netWorth = new NetWorth();
            netWorth.setDate(strs[0]);
            netWorth.setNetWorth(strs[1]);
            netWorth.setNetGains(strs[2]);
            netWorths.add(netWorth);
            log.debug(netWorth.getDate());
        }
        redisTemplate.opsForValue().set("graph:"+code+month,JSON.toJSONString(netWorths),7,
                TimeUnit.DAYS);
        log.debug("从接口获取数据");
        return netWorths;
    }

    /**
     * 获取热门基金
     *
     * @return
     * @throws Exception
     */
    @Transactional
    public List<Fund> getHot() throws Exception {
        List<Fund> funds = new ArrayList<>();
        String hotFund = redisTemplate.opsForValue().get("hotFund");
        if (hotFund != null && !"".equals(hotFund)){
            List list = JSON.parseObject(hotFund, List.class);
            for (Object o : list) {
                Fund fund = JSON.parseObject(o.toString(), Fund.class);
                funds.add(fund);
            }
            log.debug("从redis获取热门基金");
            return funds;
        }
        List<Fund> fundsFormNet = fundUtils.getFundsFormNet();
        log.debug("从接口处获取热门基金数据");
        redisTemplate.opsForValue().set("hotFund",JSON.toJSONString(fundsFormNet),3, TimeUnit.DAYS);
        return fundsFormNet;
    }
    @Transactional
    public List<Fund> getAllFund(){
        Iterable<Fund> all = fundESDao.findAll();
        return Lists.newArrayList(all);
    }

    /**
     * 根据基金code获取持仓详情
     *
     * @param code
     * @return
     * @throws URISyntaxException
     */
    @Transactional
    public JSONObject getPosition(String code) throws URISyntaxException {
        String s = redisTemplate.opsForValue().get("position:" + code);
        if (s != null && !"".equals(s)){
            log.debug("从redis获取持仓数据");
            return JSON.parseObject(s);
        }
        JSONObject position = fundUtils.getPosition(code);
        log.debug("从接口处获取持仓数据");
        redisTemplate.opsForValue().set("position:"+code,JSON.toJSONString(position),20,
                TimeUnit.DAYS);
        return position;
    }

    @Transactional
    public void changeFundStatus(Integer id){
        FundRela fundRela = fundRelaMapper.selectByPrimaryKey(id);
        if ("y".equals(fundRela.getStatus())){
            fundRela.setStatus("n");
        }else {
            fundRela.setStatus("y");
        }
        fundRelaMapper.updateByPrimaryKey(fundRela);
    }

    /**
     * 后台管理所有基金
     * @param statu
     * @return
     */
    @Transactional
    public List<FundRela> queryAllFund(String statu,Integer pageIndex,Integer pageNum){
        FundRelaExample example = new FundRelaExample();
        example.or().andStatusEqualTo(statu);
        PageHelper.startPage(pageIndex,pageNum);
        return fundRelaMapper.selectByExample(example);
    }

    /**
     * 根据基金code获取基金详情
     *
     * @param code
     * @return
     */
    @Transactional
    public FundRedis getDetailByCode(String code) {
        Optional<FundRedis> opt = fundRedisDao.findById(code);
        try {
            FundRedis fundRedis = opt.orElseThrow(RuntimeException::new);
            log.debug("从redis中获取的数据");
            return fundRedis;
        } catch (RuntimeException e) {
            try {
                FundRedis fundRedis = fundUtils.getFundDetail(code);
                fundRedisDao.save(fundRedis);
                return fundRedis;
            } catch (Exception e1) {
                log.debug("数据获取失败");
                return new FundRedis();
            }
        }
    }

    /**
     * 根据类型获取基金
     *
     * @param type
     * @return
     */
    @Transactional
    public List<Fund> getfundsByType(String type,Integer pageNum) throws Exception {
        List<Fund> funds = null;
        log.debug("页码："+pageNum);
        Pageable page = PageRequest.of(pageNum,10);
        if ("all".equals(type)){
            Iterable<Fund> all = fundESDao.findAll(page);
            funds = Lists.newArrayList(all);
        }else {
            funds = fundESDao.getAllByFundTypeEquals(type,page);
            log.debug("查询数据数量："+funds.size());
        }
        if (funds.size() > 0) {
            log.debug("从elasticSearch中获取的数据");
            fundUtils.fundSort(funds);
            return funds;
        }
        //获取要查询的基金code
        List<String> codes = getCodes("y");
        funds = fundUtils.queryFundsByCodes(codes);
        for (Fund fund : funds) {
            FundRelaExample relaExample = new FundRelaExample();
            relaExample.or().andCodeEqualTo(fund.getCode());
            List<FundRela> fundRelas = fundRelaMapper.selectByExample(relaExample);
            fund.setFundType(fundRelas.get(0).getFundtype());
        }
        fundESDao.saveAll(funds);
        if ("all".equals(type)){
            Iterable<Fund> all = fundESDao.findAll(page);
            funds = Lists.newArrayList(all);
        }else {
            funds = fundESDao.getAllByFundTypeEquals(type,page);
        }
        log.debug("从接口处获取的数据");
        fundUtils.fundSort(funds);
        return funds;
    }

    @Transactional
    public List<String> getCodes(String str) {
        FundRelaExample example = new FundRelaExample();
        if (str != null && !"".equals(str)) {
            example.or().andStatusEqualTo(str);
        }
        List<FundRela> fundRelas = fundRelaMapper.selectByExample(example);
        List<String> codes = new ArrayList<>();
        for (FundRela fundRela : fundRelas) {
            codes.add(fundRela.getCode());
        }
        return codes;
    }

}
